package com.cskaoyan.javase.array._5callby;

import java.util.Arrays;

/**
 * 方法的传值问题
 * 何为方法的传参/传值问题？
 *      在调用方法时，有时会给方法传入一个实参变量
 *      那么：
 *          这个传入方法的实参变量，如果在方法中被修改了
 *          那么对原先的实参变量有什么影响呢？
 *
 * 接下来了解方法的两种传值方式，它们是用于解释方法传参的两个概念：
 *      注：传参中的值传递和引用传递本身就是一个概念，理解原理，不要扣概念。
 *
 *  1.值传递（call by value），指的是调用方法时，传入方法的是实参变量的拷贝而不是实参本身。
 *      如果Java是值传递的，那么方法改变的是实参拷贝的值，原本实参变量的值是不会被改变的。
 *      值传递不会改变原先实参变量的取值。
 *
 *  2.引用传递（call by reference），指的是调用方法时，传入的是实参变量的地址，也就是实参本身。
 *      如果Java是引用传递的，方法改变的是实参本身的值，方法结束后，原本实参变量的值会随之改变。
 *      引用传递会改变原先实参变量的取值。
 *
 *
 * 接下来写方法验证以上结论，从两个角度验证：
 *      1.基本数据类型实参变量
 *          通过测试方法，得出：
 *          至少对于基本数据类型实参变量传入方法
 *          Java是值传递的
 *          方法不能修改基本数据类型实参变量的取值
 *          因为得到的是它的拷贝。
 *
 *      2.引用数据类型实参变量
 *          我们通过一个将数组元素变为2倍，然后成功的方法
 *          得出结论：
 *          方法可以修改引用数据类型实参变量
 *          所以对于引用数据类型实参变量
 *          Java是引用传递的
 *
 *          以上结论显然是错误的，实际上Java当中
 *          传值的方式只有值传递
 *          Java没有引用传递
 *          任何时候Java中的方法得到的都是实参变量的拷贝
 *
 *
 *  总结：Java方法对方法参数能做什么？
 *      1.不能修改基本数据类型的实参的值，也不能修改引用数据类型实参引用的取值。
 *          总之，一个方法不能修改另一个方法中局部变量的取值。
 *              这里的局部变量包括：其它方法中的基本数据类型变量和引用数据类型的引用
 *              显然这是因为Java的设计中，局部变量就仅在方法内部生效。
 *
 *     2.可以改变引用数据类型中对象里的数据（称之为改变对象的状态，改变对象的属性值）
 *          改变对象中元素取值或者属性的取值，称之为改变对象的状态
 *          方法可以改变对象的状态，但是方法不能改变引用。
 *
 * @since 09:44
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        int a = 10;
        doubleIntValue(a);
        System.out.println(a);

        System.out.println("----------------");

        int[] arr = {1, 2, 3};
        System.out.println("调用方法之前:" + Arrays.toString(arr));
        doubleArrElement(arr);
        System.out.println("调用方法之后:" + Arrays.toString(arr));

        System.out.println("-------------------");
        int[] arr1 = {666, 666, 666};
        int[] arr2 = {777, 777, 777};
        /*
            如果交换能够成功，方法得到的应该是实参变量本身（引用本身）
            那么这里应该是引用传递

            如果交换不能够成功，法得到的应该是实参变量拷贝（引用的拷贝）
            那么这里应该是值传递

         */
        System.out.println("调用方法之前arr1:" + Arrays.toString(arr1));
        System.out.println("调用方法之前arr2:" + Arrays.toString(arr2));
        swapArrReference(arr1, arr2);
        System.out.println("调用方法之后arr1:" + Arrays.toString(arr1));
        System.out.println("调用方法之后arr2:" + Arrays.toString(arr2));

    }

    // 将一个int实参变为2倍
    public static void doubleIntValue(int a) {
        a *= 2;
    }

    // 将一个int类型数组的元素变量原先的2倍
    public static void doubleArrElement(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            arr[i] *= 2;
        }
    }

    // 交换两个数组的引用
    public static void swapArrReference(int[] arr1, int[] arr2) {
        // 交换需要temp
        int[] temp = arr1;
        arr1 = arr2;
        arr2 = temp;

        System.out.println("调用方法当中arr1:" + Arrays.toString(arr1));
        System.out.println("调用方法当中arr2:" + Arrays.toString(arr2));
    }
}
